package tr.edu.yildiz.crystalapp;

import static tr.edu.yildiz.crystalapp.util.DapConstants.ANDROID_FRAMEWORK_PACKAGES;
import static tr.edu.yildiz.crystalapp.util.DapConstants.FELIX_BUNDLES_DIR;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.felix.fileinstall.DirectoryWatcher;
import org.apache.felix.fileinstall.FileInstall;
import org.apache.felix.framework.Felix;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.cache.BundleCache;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.StringMap;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

import tr.edu.yildiz.crystalapp.infra.AndroidResourceManager;
import tr.edu.yildiz.crystalapp.infra.InfraManager;
import tr.edu.yildiz.crystalapp.view.NoApplicationAvailableView;
import tr.edu.yildiz.crystalapp.view.ViewFactory;
import android.app.Activity;
import android.content.res.Resources;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

public class CrystalActivity extends Activity {
	private File cache;
	private Felix felix;
	private StringMap configMap;
	private ServiceTracker appAgentTracker; 
	
	private static String CRYSTALL_APPS = "CrystalApp";
	
	private AndroidResourceManager androidResourceManager;
	
    /** Called when the activity is first created. 
     * @throws IOException */
    @Override
    public synchronized void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        PrintStream out = new PrintStream(new OutputStream(){
        	ByteArrayOutputStream output = new ByteArrayOutputStream();
			@Override
			public void write(int oneByte) throws IOException {
				output.write(oneByte);
				if (oneByte == '\n') {
					Log.v("out", new String(output.toByteArray()));
					output = new ByteArrayOutputStream();
				}
			}});
        System.setErr(out);
        System.setOut(out);
        configMap = new StringMap(false);
        configMap.put(FelixConstants.LOG_LEVEL_PROP, String.valueOf(Logger.LOG_DEBUG));
        configMap.put(DirectoryWatcher.DEBUG, "1");
        // Configure the Felix instance to be embedded.
        configMap.put(FelixConstants.EMBEDDED_EXECUTION_PROP, "true");
        File bundles = new File(FELIX_BUNDLES_DIR);
        if (!bundles.exists()) {
        	if (!bundles.mkdirs()) {
        		throw new IllegalStateException("Unable to create bundles dir");
        	}
        }
        configMap.put("felix.auto.deploy.dir", bundles.getAbsolutePath());
      configMap.put(DirectoryWatcher.DIR, bundles.getAbsolutePath());
        // Add core OSGi packages to be exported from the class path
        // via the system bundle.
        configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES, ANDROID_FRAMEWORK_PACKAGES);
        // Explicitly specify the directory to use for caching bundles.
		try {
			cache = File.createTempFile("felix-cache", null,new File("/data/dalvik-cache/"));
		} catch (IOException ex) {
			throw new IllegalStateException(ex);
		}
        cache.delete();
        cache.mkdirs();
        configMap.put(BundleCache.CACHE_PROFILE_DIR_PROP, cache.getAbsolutePath());
    }
    
    @Override
    public synchronized void onStart() {
    	super.onStart();
		setContentView(new NoApplicationAvailableView(this));
		Resources res = getResources();
    	try {
    		List<BundleActivator> activators = new ArrayList<BundleActivator>();
    		
    		// Install the bundle installer
            activators.add(new Installer(res));
            activators.add(new AgentActivator(res));
            activators.add(new AgentInfraActivator(res));
            activators.add(new AgentAndroidActivator(res));
    		felix = new Felix(configMap, activators);
    		felix.start();
		} catch (BundleException ex) {
			throw new IllegalStateException(ex);
		}
		initViewFactory();
		initInfraManager("tr.edu.yildiz.ce.dap.appagent.service.infra.DownloadManager");
		initInfraManager("tr.edu.yildiz.ce.dap.appagent.service.infra.NetworkManager");
    }
    
    
    private void initInfraManager(String className) {
    	try {
			appAgentTracker = new ServiceTracker(felix.getBundleContext(), felix
					.getBundleContext().createFilter(
							"(" + Constants.OBJECTCLASS + "="
									+ className + ")"),
					new ServiceTrackerCustomizer() {

						@Override
						public Object addingService(ServiceReference ref) {
							Object object = felix.getBundleContext().getService(ref);
							if (!(object instanceof InfraManager))
								return object;
							final InfraManager infraManager = (InfraManager) felix
									.getBundleContext().getService(ref);
							infraManager.initActivity(CrystalActivity.this);
							if (infraManager instanceof AndroidResourceManager)
								androidResourceManager = (AndroidResourceManager) infraManager;
							return infraManager;
						}

						@Override
						public void modifiedService(ServiceReference ref,
								Object service) {
							removedService(ref, service);
							addingService(ref);
						}

						@Override
						public void removedService(ServiceReference arg0,
								Object arg1) {
							
						}
					});
			appAgentTracker.open();
		} catch (InvalidSyntaxException e) {
			e.printStackTrace();
		}
	}


	private void initViewFactory() {
		try {
			appAgentTracker = new ServiceTracker(felix.getBundleContext(), 
					felix.getBundleContext().createFilter("(" + Constants.OBJECTCLASS + "=" + ViewFactory.class.getName() + ")"), 
						new ServiceTrackerCustomizer() {

						@Override
						public Object addingService(ServiceReference ref) {
							final ViewFactory fac = (ViewFactory) felix.getBundleContext().getService(ref);
							if (fac != null) {
								runOnUiThread(new Runnable() {
									public void run() {
										setTitle(fac.getApplicationName());
										setContentView(fac.create(CrystalActivity.this));
									}
								});
							}	
							return fac;
						}

						@Override
						public void modifiedService(ServiceReference ref,
								Object service) {
							removedService(ref, service);
							addingService(ref);
						}

						@Override
						public void removedService(ServiceReference ref,
								Object service) {
							felix.getBundleContext().ungetService(ref);
							runOnUiThread(new Runnable() {
								public void run() {
									setTitle(new StringBuffer(CRYSTALL_APPS));
									setContentView(new NoApplicationAvailableView(CrystalActivity.this));
								}
							});
						}});
			appAgentTracker.open();
		} catch (InvalidSyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
    
    @Override
    public synchronized void onStop() {
        System.out.println("============= ON STOP ==========");
    	super.onStop();
    	appAgentTracker.close();
    	appAgentTracker = null;
    	felix.stopAndWait();
    	felix = null;
    }
    
    @Override
    public synchronized void onDestroy() {
    	super.onDestroy();
        System.out.println("============= ON DESTROY ==========");

    	delete(cache);
    	configMap = null;
    	cache = null;
    }
    
    private void delete(File target) {
    	if (target.isDirectory()) {
    		for (File file : target.listFiles()) {
    			delete(file);
    		}
    	}
    	target.delete();
    }
    
    public AndroidResourceManager getAndroidResourceManager() {
		return androidResourceManager;
	}
}